package com.ctd.springframework.core.io;

import com.ctd.springframework.util.Assert;
import com.ctd.springframework.util.ClassUtils;
import com.ctd.springframework.util.StringUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.Objects;

/**
 * ClassPathResource
 *
 * @author chentudong
 * @date 2019/3/24
 */
public class ClassPathResource extends AbstractFileResolvingResource {
    /**
     * path
     */
    private final String path;

    /**
     * classLoader
     */
    private ClassLoader classLoader;

    /**
     * class
     */
    private Class<?> clazz;

    public ClassPathResource(String path) {
        this(path, (ClassLoader) null);
    }

    public ClassPathResource(String path, Class<?> clazz) {
        Assert.notNull(path, "Path must not be null");
        this.path = StringUtils.cleanPath(path);
        this.clazz = clazz;
    }

    public ClassPathResource(String path, ClassLoader classLoader) {
        // path is null
        Assert.notNull(path, "Path must not be null");
        path = StringUtils.cleanPath(path);
        if (path.startsWith("/")) {
            path = path.substring(1);
        }
        this.path = path;
        this.classLoader = (Objects.nonNull(classLoader) ? classLoader : ClassUtils.getDefaultClassLoader());
    }

    /**
     * getUrl
     *
     * @return URL
     * @throws IOException IOException
     */
    @Override
    public URL getURL() throws IOException {
        return null;
    }

    /**
     * getUrl
     *
     * @return URI
     * @throws IOException IOException
     */
    @Override
    public URI getURI() throws IOException {
        return null;
    }

    /**
     * getFile
     *
     * @return File
     * @throws IOException IOException
     */
    @Override
    public File getFile() throws IOException {
        return null;
    }

    /**
     * Return a description for this resource,
     * to be used for error output when working with the resource.
     * <p>Implementations are also encouraged to return this value
     * from their {@code toString} method.
     *
     * @see Object#toString()
     */
    @Override
    public String getDescription() {
        StringBuilder builder = new StringBuilder("class path resource [");
        String pathToUse = this.path;
        if (Objects.nonNull(this.clazz) && pathToUse.startsWith("/")) {
            // get classPackageAsResourcePath
            builder.append(ClassUtils.classPackageAsResourcePath(this.clazz));
            builder.append('/');
        }
        if (pathToUse.startsWith("/")) {
            // substring
            pathToUse = pathToUse.substring(1);
        }
        builder.append(pathToUse);
        builder.append(']');
        return builder.toString();
    }

    /**
     * getInputStream
     *
     * @return InputStream
     * @throws IOException IOException
     */
    @Override
    public InputStream getInputStream() throws IOException {
        InputStream is;
        if (Objects.nonNull(this.clazz)) {
            // getResourceAsStream
            is = this.clazz.getResourceAsStream(this.path);
        } else if (Objects.nonNull(this.classLoader)) {
            is = this.classLoader.getResourceAsStream(this.path);
        } else {
            is = ClassLoader.getSystemResourceAsStream(this.path);
        }
        if (Objects.isNull(is)) {
            throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
        }
        return is;
    }
}
